/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "typedef.h"
#include "power/p33.h"
#include "hwi.h"

#define log_i printf

#define WDTEN        4
#define WDTMD         5
#define WDTCLR        6
#define    WDTINT        7

static const u32 wdt_time[] = {
    1,    2,     4,     8,
    16,   32,    64,   128,
    256,  512,  1024,  2048,
    4096, 8192, 16384, 32768,
};

void wdt_tx_con(u8 data)
{
    p33_tx_1byte(P3_WDT_CON, data);
}

void wdt_or_con(u8 data)
{
    p33_or_1byte(P3_WDT_CON, data);
}

void wdt_and_con(u8 data)
{
    p33_and_1byte(P3_WDT_CON, data);
}

u8 wdt_rx_con(void)
{
    return p33_rx_1byte(P3_WDT_CON);
}

void wdt_close(void)
{
    wdt_tx_con(0);
}

void wdt_enable(void)
{
    wdt_or_con(BIT(WDTEN));
}

void wdt_disable(void)
{
    wdt_and_con((u8)~BIT(WDTEN));
}

void wdt_clear(void)
{
    wdt_or_con(BIT(WDTCLR));
}

void clr_wdt(void)
{
    wdt_clear();
}

void wdt_set_irq(void *handler)
{
    wdt_or_con(BIT(WDTMD));
    wdt_or_con(BIT(WDTCLR));
    wdt_enable();
    JL_P33->RTC_CON |= BIT(4);
}

void wdt_clr_pending(void)
{
    wdt_clear();
}

void reset_source_dump(void);
u8 power_reset_source_dump(void);
u32 __hw_wakeup_source(void);

void trace_call_stack(void);
void wdt_isr(void)
{
    u32 tmp;
    u32 rets, reti;

    trace_call_stack();
    __asm__ volatile("%0 = rets" : "=r"(rets));
    __asm__ volatile("%0 = reti" : "=r"(reti));

    log_i("\r\n\r\n---------------------------watchdog---------------------\r\n\r\n");
    log_i("RETS = %08x \r\n", rets);
    log_i("RETI = %08x \r\n", reti);

    __asm__ volatile("%0 = sp" : "=r"(tmp));
    log_i("SP = %08x \r\n", tmp);
    __asm__ volatile("%0 = usp" : "=r"(tmp));
    log_i("USP = %08x \r\n", tmp);
    __asm__ volatile("%0 = ssp" : "=r"(tmp));
    log_i("SSP = %08x \r\n", tmp);
    while (1) {
    }
}

extern const int config_asser;
void wdt_init(u8 time)
{
    if (config_asser) {
        wdt_tx_con(0);
        wdt_tx_con(time & 0x0F);
        wdt_set_irq(wdt_isr);
        WDT_EXPT_EN(1);
    } else {
        wdt_and_con(~BIT(WDTEN));
        wdt_tx_con(0);
        wdt_tx_con(time & 0x0F);
        wdt_or_con(BIT(WDTEN));
    }
}

u32 wdt_get_time(void)
{
    u8 wdt_con = wdt_rx_con();
    if (wdt_con & BIT(WDTEN)) {
        wdt_clear();
        return wdt_time[wdt_con & 0x0f];
    }
    return 0;
}

